A Spring Boot REST API that computes prime numbers up to a given number, with algorithm selection, intelligent caching, and content negotiation for JSON and XML responses.
Try the running app first:
- API:
https://prime-api-service.onrender.com/api/primes?upTo=30&algorithm=auto - Swagger UI:
https://prime-api-service.onrender.com/swagger-ui.html - Repository:
https://github.com/AnneDoig/prime-api - Branch for review:
prime-api-final
Note: Render free-tier services may spin down after inactivity. The first request may take 30-60 seconds. Note: Browser requests may show XML due to browser
Acceptheaders. Use Swagger UI orAccept: application/jsonfor JSON.
- Assessment Requirements Checklist
- Tech Stack
- API Endpoint
- Query Parameters
- Algorithms
- Response Format (JSON and XML)
- Validation and Error Handling
- Caching and Performance
- Testing
- API Documentation (Swagger)
- Deploy Your Own (Optional)
- Run Locally
- Future Improvements
| Assessment requirement | Status | Where to see evidence |
|---|---|---|
| Project written in Java 17/20/21 | Done | Java 21 is used (within the requirement) |
| Uses Maven to build/test/run | Done | Maven wrapper commands in Run Locally |
| Unit + integration tests | Done | Testing (JUnit 5 + Karate) |
| Built on Spring Boot | Done | Spring Boot 4.0.6 in pom.xml; app structure |
| API responds with valid JSON | Done | Response Format (JSON and XML) |
| API is documented | Done | This README + API Documentation (Swagger) |
| Optional: deploy to accessible platform | Done | Live Demo (Start Here), Deploy Your Own (Optional) |
| Optional: support XML via requested media type | Done | Response Format (JSON and XML) |
| Optional: improve performance (caching/concurrency) | Done (caching) | Caching and Performance |
| Optional: multiple algorithms switchable via params | Done | Algorithms, Query Parameters |
- Java 21 / Spring Boot 4.0.6
- Maven (Maven Wrapper)
- Lombok — reduces boilerplate
- Jackson — JSON (default) and XML via
jackson-dataformat-xml - SpringDoc OpenAPI 3 — Swagger UI at
/swagger-ui.html - Caffeine 3.2.0 — bounded in-memory cache with TTL and weight-based eviction
- JUnit 5 — unit tests
- Karate 1.4.1 — integration tests
- Docker — containerised for Render deployment
Security/dependency note:
- Karate
1.4.1transitively brought vulnerable Armeria1.25.2(CVE-2023-44487). - Explicit override to Armeria
1.38.0(test scope) is included inpom.xml.
GET /api/primes?upTo=100&algorithm=autoupTo(required): positive integer, the highest number to check for primesalgorithm(optional):auto,trial,sieve,segmented-sieve- default =
auto
- default =
page(optional): page number, starts at 1 (default = 1)size(optional): number of results per page, 1-1000 (default = 100)
pagestarts at 1 (page 1 is the first page).totalPagesis the number of pages available.maxPageNumberis the highest valid page for the current request.primeCountis total primes found before splitting into pages.pagePrimeCountis the number of primes returned in the current page.
Example request:
GET /api/primes?upTo=100&algorithm=auto&page=1&size=10Example response (truncated):
{
"upTo": 100,
"source": "COMPUTED",
"requestedAlgorithm": "auto",
"resolvedAlgorithm": "trial",
"algorithmDisplay": "auto/trial",
"primeCount": 25,
"pagePrimeCount": 10,
"page": 1,
"size": 10,
"totalPages": 3,
"maxPageNumber": 3,
"hasNext": true,
"primes": [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
}Out-of-range page example:
GET /api/primes?upTo=100&algorithm=auto&page=9&size=10{
"timestamp": "2026-05-11T14:30:00+01:00",
"status": 400,
"error": "Bad Request",
"message": "Page out of range for this request. Valid page number is 1 to 3",
"path": "/api/primes"
}Supported algorithms:
auto— selects the best algorithm based on input sizetrial— trial division (best for small ranges)sieve— Sieve of Eratosthenes (best for medium ranges)segmented-sieve— memory-efficient for very large ranges
Auto thresholds currently used:
n < 10,000->trial10,000 <= n < 200,000->sieven >= 200,000->segmented-sieve
The API supports both JSON and XML through content negotiation.
- JSON can be requested with:
Accept: application/json - XML can be requested with:
Accept: application/xml
From application.properties:
spring.mvc.contentnegotiation.default-content-type=application/json
# Local API call (default browser call may show XML due to Accept header)
curl -i "http://localhost:8080/api/primes?upTo=30&algorithm=auto"
# Explicit JSON
curl -i -H "Accept: application/json" "http://localhost:8080/api/primes?upTo=30&algorithm=auto"
# Explicit XML
curl -i -H "Accept: application/xml" "http://localhost:8080/api/primes?upTo=30&algorithm=auto"- Invalid
upTo(e.g. 0, negative) returns400 Bad Request - Unsupported
algorithmreturns400 Bad Request - Values above the configured limit (default 3,000,000) return
400 Bad Request - Error responses are handled centrally by
GlobalExceptionHandlerin a standardApiErrorshape.
For each algorithm, results are cached and reused in three ways:
CACHED_EXACT— same number requested again, served directly from cacheCACHED_FILTERED— smaller request served by filtering down a larger cached resultCACHED_EXTENDED— larger request built by extending a smaller cached result
In auto mode, results cached by any algorithm can be reused across algorithm boundaries (cross-algorithm reuse), avoiding unnecessary recomputation.
If no cache is usable, response source is COMPUTED.
Design note:
autointentionally prefers the best algorithm for the requested range, then reuses cached data when safe (exact hit or filtering from a larger cached result). It does not currently extend a smaller cache across algorithms.
From application.properties:
prime.cache.max-weight=2000000prime.cache.ttl=15mprime.max-full-result-up-to=3000000
To reset in-memory caches without restarting the service:
POST /api/cache/clearExample response:
{
"message": "Cache cleared",
"clearedAlgorithms": 3,
"clearedEntries": 12
}- Large prime lists are expensive to serialize (at
upTo=3M, JSON is roughly 1-2 MB). - The upper limit is configurable via
prime.max-full-result-up-to. - Cache weight and TTL are configurable to balance speed and memory.
This project includes:
- Unit tests (JUnit 5) for prime logic, algorithm selection, cache behaviour, and validation
- Integration tests (Karate) for endpoint behaviour and error responses
Run all tests:
./mvnw testKarate HTML report:
target/karate-reports/karate-summary.html
Test coverage includes:
- algorithm correctness and auto thresholds
- cache-source behaviour (
CACHED_EXACT,CACHED_FILTERED,CACHED_EXTENDED) - cross-algorithm cache reuse in
automode - invalid input handling (
upTo,algorithm,page,size) - max-limit validation (
ResponseStatusExceptionpath)
- Local:
http://localhost:8080/swagger-ui.html - Live:
https://prime-api-service.onrender.com/swagger-ui.html
This project includes a Dockerfile and is ready to deploy on Render.
- Push your branch to GitHub
- In Render, create a new Web Service and connect your repository
- Set:
- Environment:
Docker - Branch: your target branch (
prime-api-final) - Port: Render sets
PORT; app reads${PORT:8080}
- Environment:
- Deploy
Once live, your endpoints are typically:
https://<your-app>.onrender.com/api/primes?upTo=100&algorithm=auto
https://<your-app>.onrender.com/swagger-ui.html
- Clone the repository
- Build:
./mvnw clean package- Run the JAR:
java -jar target/prime-api-0.0.1-SNAPSHOT.jar- Open:
- API:
http://localhost:8080/api/primes?upTo=100&algorithm=auto - Swagger UI:
http://localhost:8080/swagger-ui.html
./mvnw spring-boot:run- Persistent cache (PostgreSQL) for summary results across restarts
- Redis distributed cache for shared cache in scaled deployments
- Request audit logging for analytics/observability
- Cross-algorithm upward cache reuse in
automode